The Memory Manager

 

This part of the manual covers one of the central features of the system runtime. It requires some basic understanding of C. If you are a beginner, skip this chapter and remember: To get more memory, use the function GC_malloc(), and forget the rest. No free() or other items are required.

 

Lcc-win32 features the garbage collector developed by Hans J. Boehm and Alan J. Demers. This fine piece of public software allows you to program in C from a different, much more relaxed perspective.

 

The well-known problem with manual memory management is that it is very difficult for a person to specify without any error when each memory block used will be destroyed and recycled by the runtime system.

 

This is a task that is better left to a machine, i.e., a computer. The authors of this software have solved the memory management problem, eliminating countless debugging hours.

 

There are, of course, applications where real-time requirements make the usage of the automatic memory manager impossible. Those applications can still use the default memory manager (a much slower solution) or devise a memory manager tailored to the application, as all C programmers do, in one way or another.

 

For most applications, however, the time required for the memory manager to accomplish its task will be unnoticeable. The authors’ years of development have fine tuned the software. The speed of the automatic memory manager exceeds that of the standard “malloc” implementation by a factor of greater than 10!

 

The development speed is another important factor. You can concentrate more on what the program is doing and if its doing it well now without having to focus on each bit of RAM you are using. It is no longer necessary to develop a memory manager for each application. A DLL and a link time import library are the only requirements.

 

The debugging time required by manual collection must also be taken into consideration. Problems in this area are quite difficult to locate. A memory leak or a mistake like calling free twice can cause a long search and hours lost in the debugger. If you ever find the problem at all. There are numerous examples of programs with this type of problem that are never corrected: it is just too hard to follow. When the symptoms appear, there is a crash, etc., the real problem can be far removed. Reconstructing the route from the destroyed data to the error can take an immense amount of time.

 

Consider too, the realities of the lcc-win32 implementation. The malloc runtime function furnished with the Windows system is quite possibly the worst implementation available. When compiled for the standard memory allocator, Wedit takes 80 seconds to load an 8 MB project. This time is reduced to only 5 seconds with the collector.

 

You should know, however, that the memory manager requires a few simple rules to operate properly. These rules are common sense, so they are easy to understand and follow.

 

 

Preparing your Programs for Use with the Memory Manager

Below are a few simple rules to follow when using the memory manager.

1.      Never store pointers to objects allocated with the collector in inaccessible places. For instance:

·        Do not store pointers in the window extra bytes, without keeping a pointer somewhere in memory to indicate to the collector which object is being used. The memory manager has no access to pointers inside the system’s data structures. It will therefore assume that memory can be reclaimed, resulting in problems in your program.

·        Do not store pointers at odd addresses or at addresses that are not a multiple of four. The compiler and the linker align the memory so that this is the case for all your data when the program starts. Thereafter, you must follow this rule.

2.      Do not store pointers in arrays declared as integers or in DWORDs. The compiler generates type information and makes special calls to the memory manager when the object allocated contains no pointers. Basically, it tells the collector to ignore those memory locations, since they do not contain pointers. If you circumvent this with casts, the collector will not know that the data are being used and will reclaim them.

3.      It is better, though not required, to set all pointers that are no longer is use to ZERO to avoid retaining too much data unnecessarily. If you do not do this, the data will be retained until the scope of the pointer is finished. Pointers stored in global variables remain indefinitely, so that the data they point to will never be reclaimed and the program will leak. A similar situation holds for pointers stored as local variables in the main() function

4.      You should link with gc.lib, which is the import library of gc.dll. For technical reasons, it is not possible to link statically with the gc. It must be a DLL. This means that when you ship your program, it must be shipped with the gc.dll .[1]

 

The C Interface to the Collector

This interface is described in greater detail in the on-line documentation. It will not be repeated here. You can find it if you go to the « index » item in the help menu, and choose the memory manager link.

 

Function

Description

void *GC_malloc(size_t size) ;

Returns to the address of a new memory block start. The object can contain pointers to other objects.

void * GC_malloc_atomic(size_t size) ;

Returns to the address of a new memory block start, which cannot contain pointers.

void *GC_realloc(void *oldObject,size_t newSize) ;

Resizes the given object.

void *GC_malloc_ignore_off_page( size_t) ;

Large objects (> 100K) should be allocated using this function.

size_t GC_size(void *object) ;

Returns the size in bytes of the given object.

 

 



[1] The memory manager must be informed by the system when the program starts a new thread. The stack of the new thread must be recorded. This is not possible with a static library. The collector data structures are protected with semaphores, but the collector must stop all other threads to avoid being called when a collection is not finished.